package com.quanyan.ic.vendingMachine.http.service.impl;

import com.alibaba.fastjson.JSON;
import com.quanyan.ic.vendingMachine.constant.PayStatus;
import com.quanyan.ic.vendingMachine.dao.VmGridGoodsMappingDAO;
import com.quanyan.ic.vendingMachine.dao.VmInventoryDAO;
import com.quanyan.ic.vendingMachine.dao.VmOrderDAO;
import com.quanyan.ic.vendingMachine.dao.VmPlaceMappingDAO;
import com.quanyan.ic.common.http.exception.BizException;
import com.quanyan.ic.vendingMachine.http.service.VmOrderService;
import com.quanyan.ic.vendingMachine.model.*;
import com.quanyan.ic.vendingMachine.remoting.InventoryRemotingService;
import com.quanyan.ic.vendingMachine.remoting.OrderRemotingService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by zhuo.shi on 2017/8/2.
 */
@Service
public class VmOrderServiceImpl implements VmOrderService {

    private static Logger logger = LoggerFactory.getLogger(VmOrderServiceImpl.class);

    @Autowired
    private VmPlaceMappingDAO vmPlaceMappingDAO;
    @Autowired
    private VmOrderDAO vmOrderDAO;
    @Autowired
    private OrderRemotingService orderRemotingService;
    @Autowired
    private VmGridGoodsMappingDAO vmGridGoodsMappingDAO;
    @Autowired
    private VmInventoryDAO vmInventoryDAO;
    @Autowired
    private InventoryRemotingService inventoryRemotingService;

    /**
     * 根据订单号查询订单详情
     *
     * @param orderNo 订单号
     * @return
     */
    @Override
    public OrderInfo findOrder(String orderNo) {
        if (StringUtils.isEmpty(orderNo)) {
            return null;
        }
        return vmOrderDAO.findOrder(orderNo);
    }

    /**
     * 立即支付，预下单
     *
     * @param shoppingCart 购物车信息
     * @return
     */
    @Transactional
    @Override
    public OrderPreparedResult scanQrCodePay(ShoppingCart shoppingCart, HttpServletRequest request) {
        //1. 查找售货机信息，校验参数
        String vmNumber = shoppingCart.getVmNumber();
        VmPlaceMapping vmPlaceMapping = vmPlaceMappingDAO.findByVmNumber(vmNumber);
        if (vmPlaceMapping == null) {
            throw new BizException("没有找到售货机[" + vmNumber + "]");
        }
        //2. 校验价格和库存，防篡改
        List<ShoppingCartItem> shoppingCartItems = shoppingCart.getShopingCartInfo();
        for (ShoppingCartItem shoppingCartItem : shoppingCartItems) {
            String grid = shoppingCartItem.getGrid();
            Byte gridNumber = shoppingCartItem.getGridNumber();
            GridGoodsMapping gridGoodsMapping = vmGridGoodsMappingDAO.find(vmNumber, grid, gridNumber);
            if (gridGoodsMapping == null || gridGoodsMapping.getGoodsInfo() == null) {
                throw new BizException("货道[" + grid + "]没有任何关联的商品");
            }
            GoodsInfo goodsInfo = gridGoodsMapping.getGoodsInfo();      //货道现在的商品信息
            Double price = shoppingCartItem.getPrice();
            if (price.doubleValue() != goodsInfo.getPrice()) {
                throw new BizException("货道[" + grid + "]的商品[" + goodsInfo.getName() + "]，售价为[" + goodsInfo.getPrice() + "]，但订单价格为[" + price + "]");
            }
            Integer qty = shoppingCartItem.getQty();
            if (qty > gridGoodsMapping.getInventory()) {
                throw new BizException("货道[" + grid + "]的商品库存仅剩[" + gridGoodsMapping.getInventory() + "]，但购买数量为[" + qty + "]");
            }
            shoppingCartItem.setInventory((int) gridGoodsMapping.getInventory());
            shoppingCartItem.setImg(gridGoodsMapping.getGoodsInfo().getImg());
        }
        //3. 调用场馆小商品预下单服务
        Integer placeId = vmPlaceMapping.getPlaceId();
        OrderPreparedResult result = orderRemotingService.preOrder(placeId, vmNumber, shoppingCartItems, request);
        if (result == null) {
            throw new BizException("预下单失败，请重试！");
        }
        //4. 记录订单信息（预下单）
        OrderInfo orderInfo = toOrderInfo(shoppingCart, result);
        logger.info("Completed scanQrCodePay: \norderInfo={}\nresult={}", JSON.toJSONString(orderInfo), JSON.toJSONString(result));
        vmOrderDAO.insertOrder(orderInfo);
        //5. 填充商品清单，返回
        result.setShopingCartInfo(shoppingCartItems);
        return result;
    }

    /**
     * 转化购物车为订单信息
     *
     * @param shoppingCart 购物车信息
     * @param result       预下单结果
     */
    private OrderInfo toOrderInfo(ShoppingCart shoppingCart, OrderPreparedResult result) {
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setVmNumber(shoppingCart.getVmNumber());
        orderInfo.setOrderNo(result.getOrderNo());
        orderInfo.setAliPayCode(result.getAliPayCode());
        orderInfo.setWchatPayCode(result.getWchatPayCode());
        List<ShoppingCartItem> items = shoppingCart.getShopingCartInfo();
        double totalAmount = 0;
        List<OrderItem> orderItems = new ArrayList<>();
        for (ShoppingCartItem item : items) {
            if (item.getId() == null || StringUtils.isEmpty(item.getUuid())
                    || item.getPrice() == null || item.getQty() == null) {
                logger.warn("shoppingCart item {} no goods info", JSON.toJSONString(item));
                continue;
            }
            Double price = item.getPrice();
            totalAmount += price;
            OrderItem orderItem = new OrderItem();
            orderItem.setOrderNo(result.getOrderNo());
            orderItem.setVmNumber(shoppingCart.getVmNumber());
            orderItem.setGrid(item.getGrid());
            orderItem.setGridNumber(item.getGridNumber());
            GoodsInfo goodsInfo = new GoodsInfo();
            goodsInfo.setId(item.getId());
            goodsInfo.setUuid(item.getUuid());
            goodsInfo.setName(item.getName());
            goodsInfo.setPrice(item.getPrice());
//            goodsInfo.setCategoryId();
//            goodsInfo.setCategoryName();
            orderItem.setGoodsInfo(goodsInfo);
            orderItems.add(orderItem);
            orderItem.setQty(item.getQty().byteValue());
        }
        orderInfo.setTotalAmount(new BigDecimal(totalAmount));
        orderInfo.setItems(orderItems);
        return orderInfo;
    }

    /**
     * 订单支付后回调结果处理
     *
     * @param result 回调返回结果
     * @return
     */
    @Override
    public OrderPaySuccessResult processOrderPayCallback(OrderCallbackResult result) {
        if (result == null || StringUtils.isEmpty(result.getOrderNo())) {
            return null;
        }
        String orderNo = result.getOrderNo();
        //1. 校验订单有效性
        OrderInfo orderInfo = vmOrderDAO.findOrder(orderNo);
        if (orderInfo == null) {
            logger.warn("can't find the order {} in vm_order table", orderNo);
            return null;
        }
        if (orderInfo.getPayStatus() != PayStatus.NO_PAY.getValue()) {       //订单还是未支付状态，才处理回调，防止重复执行回调方法
            logger.warn("order {} already processed, payStatus={}", orderNo, orderInfo.getPayStatus());
            return null;
        }
        //2. 更新订单状态
        if (result.getPayStatus() != 2) {
            logger.warn("order {} not pay or pay failed, callback ignore!");
            return null;
        }
        vmOrderDAO.updateOrderPayInfo(orderNo, null, result.getPayWay(), (byte) PayStatus.PAY_SUCCESS.getValue(), System.currentTimeMillis());
        //3. 组装订单商品列表，依次发送命令通知客户端出货
        OrderPaySuccessResult opsResult = new OrderPaySuccessResult();
        opsResult.setVmNumber(orderInfo.getVmNumber());
        opsResult.setOrderItemList(orderInfo.getItems());
        return opsResult;
    }

    /**
     * 订单里的商品出货后，更新每个商品的出货状态出货数量，扣减此商品所在货道的库存
     *
     * @param vmNumber      售货机编号
     * @param orderItemList 订单商品列表
     */
    @Transactional
    @Override
    public void processOrderShipGoods(String vmNumber, List<OrderItem> orderItemList) {
        if (StringUtils.isEmpty(vmNumber) || CollectionUtils.isEmpty(orderItemList)) {
            return;
        }
        for (OrderItem orderItem : orderItemList) {
            String orderNo = orderItem.getOrderNo();
            String grid = orderItem.getGrid();
            Byte gridNumber = orderItem.getGridNumber();
            OrderItem item = vmOrderDAO.findOrderItem(orderNo, vmNumber, gridNumber);
            int shipQty = orderItem.getShipQty().intValue();
            if (item == null) {
                logger.warn("ship goods: can't find orderItem {} {} {} {}, shipQty={}", orderNo, vmNumber, grid, gridNumber, shipQty);
                continue;
            }
            byte shipStatus = item.getShipStatus();
            if (shipQty == 0) {
                //出货失败
                shipStatus = 2;
            }
            if (shipQty > 0) {
                shipStatus = 1;  //只要出货量>0都认为出货成功
            }
            vmOrderDAO.updateOrderItemShipInfo(item.getId(), shipStatus, (byte) (item.getShipQty() + orderItem.getShipQty()), System.currentTimeMillis());
            boolean ret = vmInventoryDAO.updateGridInventory(vmNumber, grid, gridNumber, (-1 * shipQty));
            if (!ret) {
                logger.error("ship goods: failed, deducting inventory, {} {} {} {}, shipQty={}", orderNo, vmNumber, grid, gridNumber, shipQty);
                throw new BizException("扣减库存失败, " + orderNo + " " + vmNumber + " " + grid + " " + gridNumber + " " + shipQty);
            }
            if (shipQty == 0) {
                logger.info("ship goods: FL, {} {} {} {}, qty={} shipQty={}", orderNo, vmNumber, grid, gridNumber, item.getQty(), shipQty);
                return;
            }

            //记录流水
            VmPlaceMapping vmPlaceMapping = vmPlaceMappingDAO.findByVmNumber(vmNumber);
            if (vmPlaceMapping == null) {
                throw new BizException("无售货机");
            }
            GridGoodsMapping gridGoodsMapping = vmGridGoodsMappingDAO.find(vmNumber, grid, gridNumber);
            if (gridGoodsMapping == null) {
                logger.info("ship goods: can't find gridGoodsMapping, {} {} {} {}, shipQty={}", orderNo, vmNumber, grid, gridNumber, shipQty);
                throw new BizException("扣减库存失败, " + orderNo + " " + vmNumber + " " + grid + " " + gridNumber + " " + shipQty);
            }
            //记录中央总库存变动流水
            GoodsOperateRecord record = new GoodsOperateRecord();
            record.setPlaceId(vmPlaceMapping.getPlaceId());
            record.setPlaceOrderId(item.getOrderNo());
            record.setPlaceStore(vmNumber);
            record.setOperateType(1);
            record.setRemark("售卖机出货");
            record.setGoodsId(item.getGoodsInfo().getUuid());
            record.setOperateCount(shipQty);
            int inventoryOfGoods = vmInventoryDAO.countVmInventoryOfGoods(vmNumber, item.getGoodsInfo().getId(), item.getGoodsInfo().getUuid());
            record.setOpBeforeCount(inventoryOfGoods);
            record.setOpAfterCount(inventoryOfGoods - shipQty);
            inventoryRemotingService.insertGoodsCenterOperateRecord(record);
            //记录售货机库存变动流水
            InventoryStream stream = new InventoryStream();
            stream.setVmNumber(vmNumber);
            stream.setOriginalInventory(gridGoodsMapping.getInventory());
            ReplenishmentInfo rsptInfo = new ReplenishmentInfo();
            rsptInfo.setGrid(grid);
            rsptInfo.setGridNumber(gridNumber);
            GoodsInfo goodsInfo = gridGoodsMapping.getGoodsInfo();
            if (goodsInfo != null) {
                rsptInfo.setGoodsId(goodsInfo.getId());
                rsptInfo.setGoodsUuid(goodsInfo.getUuid());
                rsptInfo.setGoodsName(goodsInfo.getName());
                rsptInfo.setGrid(grid);
                rsptInfo.setGridNumber(gridNumber);
                rsptInfo.setRsptCount(shipQty);
            }
            stream.setOpCount(-1 * shipQty);
            stream.setReplenishmentInfo(rsptInfo);
            vmInventoryDAO.insertInventoryStream(stream);
            logger.info("ship goods: OK, {} {} {} {}, qty={} shipQty={}", orderNo, vmNumber, grid, gridNumber, item.getQty(), shipQty);
        }
    }
}
